/**
 * 
 */
package gmu.drr.runSynthSimple;


import java.io.*;
import java.util.Properties;

import cern.jet.random.*;
import cern.jet.random.engine.*;

import gmu.drr.entity.*;
import gmu.drr.entity.netFactory.*;
import gmu.drr.modelInst.*;
import gmu.drr.modelInst.simple.*;
/**
 * @author RothmD01
 *
 */
public class SynthSimple {

	@SuppressWarnings("unchecked")
	private static SynthSimpleParameters processProperties( String propsFileName ) {
		Properties props, propsDefault;
		FileInputStream inStream = null;
		
		propsDefault = SynthSimpleParameters.getDefault();
		
		props = new Properties( propsDefault );
		
		if( propsFileName != null ) {
			try {
				inStream = new FileInputStream( propsFileName );
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}

			try {
				props.load(inStream);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		/**
		 * catalog of known properties
		 */
		String strHolder = null;
		int intHolder = 0;
		double dblHolder = 0.0;
		SynthSimpleParameters params = new SynthSimpleParameters();
		params.origProps = props;
		params.modelName = new String( props.getProperty( "ModelName") );
		strHolder = props.getProperty("Model");
		try {
			Class foo = Class.forName(strHolder);
			params.model = (ModelModel) foo.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		strHolder = props.getProperty("ModelFactory");

		/*			tmpModelFactoryClass = (Class<ModelFactory>) Class.forName(strHolder);
			Method tmpMeth = tmpModelFactoryClass.getMethod("getInstance", null);*/
		// TODO Simple and straightforward....
		params.modelFactory = ModelFactorySimple.getInstance();

		strHolder = props.getProperty("FactoryRandomSeed");
		intHolder = Integer.parseInt(strHolder);
		params.factoryRandomSeed = intHolder;
		
		strHolder = props.getProperty("FactoryRandomEngine");
		// TODO keeping it simple.... 
		params.factoryRandomEngine = new MersenneTwister( params.factoryRandomSeed );
		/*try {
			params.factoryRandomEngine = (RandomEngine) Class.forName(strHolder).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}*/

		
		strHolder = props.getProperty("NumberUsers");
		intHolder = Integer.parseInt(strHolder);
		params.numberUsers = intHolder;
		strHolder = props.getProperty("NumberUserGroups");
		intHolder = Integer.parseInt(strHolder);
		params.numberUserGroups = intHolder;
		
		strHolder = props.getProperty("NumberDocs");
		intHolder = Integer.parseInt(strHolder);
		params.numberDocs = intHolder;
		strHolder = props.getProperty("NumberDocGroups");
		intHolder = Integer.parseInt(strHolder);
		params.numberDocGroups = intHolder;
		
		strHolder = props.getProperty("DocGroupRel");
		try {
			Class<DocGroupRelModel> foo = (Class<DocGroupRelModel>) Class.forName(strHolder);
			params.docGroupRel = (DocGroupRelSimple) foo.newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		/*
		strHolder = props.getProperty("DocGroupRelWeightDist");
		try {
			params.docGroupRelWeightDist = (AbstractContinousDistribution) Class.forName(strHolder).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		*/
		
		strHolder = props.getProperty("DocGroupRelWeightParA");
		dblHolder = Double.parseDouble(strHolder);
		params.docGroupRelWeightParA= dblHolder;
		strHolder = props.getProperty("DocGroupRelWeightParB");
		dblHolder = Double.parseDouble(strHolder);
		params.docGroupRelWeightParB = dblHolder;
		
		// note the userDegree parameter, but don't stash it anywhere
		strHolder  = props.getProperty("UserDegree");
		strHolder = props.getProperty("UserDegreeWeight");
		dblHolder = Double.parseDouble(strHolder);		
		params.userDegreeWeight = dblHolder;

		strHolder = props.getProperty("NetEdgeWeight");
		try {
			params.netEdgeWeight = (NetEdgeWeightModel) Class.forName(strHolder).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		// for the simple model case, each edge has a single weight [0..1], Poisson distributed 
		/*
		strHolder = props.getProperty("NetEdgeWeightDist");
		try {
			params.netEdgeWeightDist = (AbstractContinousDistribution) Class.forName(strHolder).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		*/
		strHolder = props.getProperty("NetEdgeWeightParA");
		dblHolder = Double.parseDouble(strHolder);
		params.netEdgeWeightParA = dblHolder;
		strHolder = props.getProperty("NetEdgeWeightParB");
		dblHolder = Double.parseDouble(strHolder);
		params.netEdgeWeightParB = dblHolder;
		
		strHolder = props.getProperty("NetNodeAct");
		try {
			params.netNodeAct = (NetNodeActModel) Class.forName(strHolder).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

		/*
		strHolder = props.getProperty("NetNodeActThreshDist");
		try {
			params.netNodeActThreshDist = (AbstractContinousDistribution) Class.forName(strHolder).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		*/
		strHolder = props.getProperty("NetNodeActThreshParA");
		dblHolder = Double.parseDouble(strHolder);
		params.netNodeActThreshParA = dblHolder;
		strHolder = props.getProperty("NetNodeActThreshParB");
		dblHolder = Double.parseDouble(strHolder);
		params.netNodeActThreshParB = dblHolder;

		/*
		strHolder = props.getProperty("NetNodeActExcDist");
		try {
			params.netNodeActExcDist = (AbstractContinousDistribution) Class.forName(strHolder).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		*/
		
		// the mean of the poisson distribution
		strHolder = props.getProperty("NetNodeActExcParA");
		dblHolder = Double.parseDouble(strHolder);
		params.netNodeActExcParA = dblHolder;
		strHolder = props.getProperty("NetNodeActExcParB");
		dblHolder = Double.parseDouble(strHolder);
		params.netNodeActExcParB = dblHolder;
		// TODO this should be deferred until later - we want to assemble the excitation and suppression models with distributions drawing from
		//  the simulation engines, not the construction engines..
		/*
		strHolder = props.getProperty("NetNodeActExcSimDist");
		try {
			params.netNodeActExcSimDist = (AbstractContinousDistribution) Class.forName(strHolder).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

		strHolder = props.getProperty("NetNodeActSupDist");
		try {
			params.netNodeActSupDist = (AbstractContinousDistribution) Class.forName(strHolder).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		*/
		
		strHolder = props.getProperty("NetNodeActSupParA");
		dblHolder = Double.parseDouble(strHolder);
		params.netNodeActSupParA = dblHolder;
		strHolder = props.getProperty("NetNodeActSupParB");
		dblHolder = Double.parseDouble(strHolder);
		params.netNodeActSupParB = dblHolder;
		strHolder = props.getProperty("NetNodeActSupSimDist");
		// TODO this should be deferred until later - we want to assemble the excitation and suppression models with distributions drawing from
		//  the simulation engines, not the construction engines..
		/*
		try {
			params.netNodeActSupSimDist = (AbstractContinousDistribution) Class.forName(strHolder).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		*/

		strHolder = props.getProperty("UserGroupRel");
		try {
			params.userGroupRel = (UserGroupRelModel) Class.forName(strHolder).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		/*
		strHolder = props.getProperty("UserGroupRelWeightDist");
		try {
			params.userGroupRelWeightDist = (AbstractContinousDistribution) Class.forName(strHolder).newInstance();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		*/
		strHolder = props.getProperty("UserGroupRelWeightParA");
		dblHolder = Double.parseDouble(strHolder);
		params.userGroupRelWeightParA = dblHolder;
		strHolder = props.getProperty("UserGroupRelWeightParB");
		dblHolder = Double.parseDouble(strHolder);
		params.userGroupRelWeightParB = dblHolder;

		return params; 
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SynthSimpleParameters params;
		
		// TODO parse command line arguments
		//
		// (possibly) parse properties file (if supplied on command line) 
		params = processProperties( "modParams.params" );
		
		/** TEMP **/
	/*	File outFile = new File( "baseParams.params");
		PrintStream outPrt = null;
		try {
			outPrt = new PrintStream( outFile );
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		params.origProps.list(outPrt);*/
		// construct network (based on draw from distributions - not from data)
		// populate preferences into network
		ModelFactorySimple factory;
		factory = (ModelFactorySimple) params.modelFactory;
		factory.setParams(params);
		ModelSimple model;
		model = factory.buildModel();


		// persist assembled network
		// run simulation
		// persist output (if indicated in preferences??)
		// conduct basic analysis
		// persist analysis (if indicated in preferences??)
	}

}
